﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using CardLib;
using System.Diagnostics;

namespace Durak_Game
{
    class Durak
    {
        private Deck deck;
        private List<CardBox> computerCards;
        private List<CardBox> myCards;
        private CardBox topCard;

        private List<Card> playingCards = new List<Card>();
        private CardValues[] playingCardValues = {CardValues.Ace,CardValues.Six,CardValues.Seven,CardValues.Eight,CardValues.Nine,CardValues.Ten,
                                          CardValues.Jack,CardValues.Queen,CardValues.King};
        private CardSuits[] playingCardSuits = { CardSuits.Club, CardSuits.Diamond, CardSuits.Heart, CardSuits.Spade };

        private Label computerCardsLeft;
        private Label myCardsLeft;
        private Label remaingCardsLeft;
        private Label computerAttackerLabel;
        private Label userAttackerLabel;
        private Panel table;
        private Panel computerDesk;
        private Panel myDesk;
        private CardSuits trumpSuite;
        private List<CardBox> tableCards;
        private static int COMPUTER = 1;
        private static int ME = 2;

        private int nowPlaying = 0;
        private Form1 ui;
        int top = 1;
        private String logFileName = "log.txt";
        private Boolean gameOver = false;

        private int attacker;

        public Durak()
        {
            deck = new Deck();
            /*Initialise the list of cards gameCards with all the cards
             * that are needed in the game. 
            **/
            for (int i = 0; i < playingCardSuits.Length; i++)
            {
                for (int j = 0; j < playingCardValues.Length; j++)
                {
                    Card card = new Card(playingCardSuits[i], playingCardValues[j]);
                    playingCards.Add(card);

                }
            }

            /** Set the playing cards to deck */
            deck.Cards = playingCards;
            tableCards = new List<CardBox>();

        }
        public void setComputerCards()
        {
            StackTrace stackTrace = new StackTrace();
            log(stackTrace.GetFrame(0).GetMethod().Name);

            this.computerCards = new List<CardBox>();
            for (int i = 0; i < 6; i++)
            {
                CardBox box = new CardBox();
                this.computerCards.Add(box);
            }
            foreach (CardBox cardbox in this.computerCards)
            {

                Card deckDard = deck.GetRandomCard();
                cardbox.setCard(deckDard);
            }
            computerCardsLeft.Text = "Cards Left : " + computerCards.Count;
            arrangeComputerCards();

        }
        public void setMyCards()
        {
            StackTrace stackTrace = new StackTrace();
            log(stackTrace.GetFrame(0).GetMethod().Name);

            this.myCards = new List<CardBox>(6);

            for (int i = 0; i < 6; i++)
            {
                CardBox box = new CardBox();
                box.Cursor = Cursors.Hand;
                box.Tag = i + 1;
                box.cardBoxClicked += (s, e) =>
                {

                    playGame((int)box.Tag);
                };
                this.myCards.Add(box);
            }
            foreach (CardBox cardbox in this.myCards)
            {

                Card deckDard = deck.GetRandomCard();
                cardbox.setCard(deckDard);
                cardbox.flipCard();
            }
            myCardsLeft.Text = "Cards Left : " + myCards.Count;
            arrangeMyCards();

        }

        private void arrangeComputerCards()
        {
            StackTrace stackTrace = new StackTrace();
            log(stackTrace.GetFrame(0).GetMethod().Name);
            int x = 10;
            int y = 10;
            int xCount = 100;
            if (computerCards.Count > 12)
            {
                xCount = 50;
            }
            foreach (CardBox computerCard in this.computerCards)
            {
                computerCard.SetBounds(x, y, 94, 125);

                computerDesk.Controls.Add(computerCard);
                computerCard.BringToFront();

                x += xCount;



            }
        }

        private void arrangeMyCards()
        {
            StackTrace stackTrace = new StackTrace();
            log(stackTrace.GetFrame(0).GetMethod().Name);

            int x = 10;
            int y = 10;
            //CardBox myCard in this.myCards
            int xCount = 100;
            if (myCards.Count > 12)
            {
                xCount = 50;
            }
            int i = 1;
            foreach (CardBox myCard in this.myCards)
            {
                myCard.SetBounds(x, y, 94, 125);
                myCard.Tag = i;
                myDesk.Controls.Add(myCard);
                myCard.BringToFront();
                i++;
                x += xCount;



            }
        }
        public void setTopCard(CardBox card)
        {
            StackTrace stackTrace = new StackTrace();
            log(stackTrace.GetFrame(0).GetMethod().Name);

            this.topCard = card;
            this.topCard.setCard(deck.GetRandomCard());
            this.topCard.flipCard();
            remaingCardsLeft.Text = "Remaining Cards \n        " + (deck.NumberOfCards + 1);
            trumpSuite = topCard.getCard().Suit;
            deck.setTrumphCard(topCard.getCard());

        }
        public void setLabels(Label lbl1, Label lbl2, Label lbl3,Label lbl4,Label lbl5)
        {
            StackTrace stackTrace = new StackTrace();
            log(stackTrace.GetFrame(0).GetMethod().Name);

            this.computerCardsLeft = lbl1;
            this.myCardsLeft = lbl2;
            this.remaingCardsLeft = lbl3;
            this.computerAttackerLabel = lbl4;
            this.userAttackerLabel = lbl5;
        }
        public void setPanels(Panel table, Panel computerPanel, Panel myPanel)
        {
            StackTrace stackTrace = new StackTrace();
            log(stackTrace.GetFrame(0).GetMethod().Name);
            this.table = table;
            this.computerDesk = computerPanel;
            this.myDesk = myPanel;
        }

        public void playGame(int clickedCardIndex)
        {
            StackTrace stackTrace = new StackTrace();
            log(stackTrace.GetFrame(0).GetMethod().Name);

            if (nowPlaying != Durak.ME)
            {
                PopUp("You cant place this card");
                log("User Attempt to place invalid card");
                return;
            }
            if (gameOver)
            {
                return;
            }

            if (isValidMove(myCards, clickedCardIndex - 1))
            {
                log("User : valid Move ");
                putCardOnTable(myCards, clickedCardIndex - 1);
                nowPlaying = Durak.COMPUTER;
                computerPutACard();
            }
            else
            {
                CardBox clickedCard = myCards.ElementAt<CardBox>(clickedCardIndex - 1);
                Card card = clickedCard.getCard();
                PopUp("Sorry... Can't place that card : " + card.ToString());
                log(" User :Invalid move attempted");
            }

            //cardBox.Parent = table;

        }
        public Boolean isValidMove(List<CardBox> cards, int clickedCardIndex)
        {

            StackTrace stackTrace = new StackTrace();
            log(stackTrace.GetFrame(0).GetMethod().Name);

            if (tableCards.Count() <= 0) // First chance, when no cards on the table
            {
                return true;
            }

            CardBox clickedCard = cards.ElementAt<CardBox>(clickedCardIndex);
            Card card = clickedCard.getCard();

            /* if (card.Suit == trumpSuite && card.getCardRank()>topCard.getCard().getCardRank())
             {
                 return true;
             }*/

            if (tableCards.Count == 1)
            {
                CardBox tableCardBox = tableCards.ElementAt<CardBox>(0);
                Card tableCard = tableCardBox.getCard();
                if (card.Suit == tableCard.Suit && card.getCardRank() > tableCard.getCardRank())
                {
                    return true;
                }
            }
            else
            {
                CardBox tableCardBox1 = tableCards.ElementAt<CardBox>(0);
                Card tableCard1 = tableCardBox1.getCard();
                CardBox tableCardBox2 = tableCards.ElementAt<CardBox>(1);
                Card tableCard2 = tableCardBox2.getCard();
                if (tableCards.Count() == 2 || tableCards.Count % 2 == 0)
                {
                    if (card.getCardRank() == tableCard1.getCardRank() || card.getCardRank() == tableCard2.getCardRank())
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }

                }
                else
                {
                    CardBox topTableCard = tableCards.ElementAt<CardBox>(tableCards.Count - 1);
                    Card topCard = tableCardBox1.getCard();
                    if (card.getCardRank() == tableCard2.getCardRank() && card.Suit == topCard.Suit)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }


                }



            }



            /*int tableRank = -1;
            CardSuits tableSuit = CardSuits.Club;
            foreach (CardBox cardbox in tableCards)
            {
                Card tableCard = cardbox.getCard();
                if (tableCard.getCardRank() > tableRank)
                {
                    tableRank = tableCard.getCardRank();
                    tableSuit = tableCard.Suit;
                }
            }

           
            for (int i = 0; i < tableCards.Count; i++)
            {
                CardBox tableCardBox = tableCards.ElementAt<CardBox>(i);
                Card tableCard = tableCardBox.getCard();
                if (card.Suit == tableCard.Suit && card.getCardRank()>tableRank)
                {
                    return true;
                }
            }*/

            return false;
        }
        public void startGame()
        {

            StackTrace stackTrace = new StackTrace();
            log(stackTrace.GetFrame(0).GetMethod().Name);
            nowPlaying = findAttacker();
            if (nowPlaying == Durak.COMPUTER)
            {

                PopUp("Computer is the attacker");
                computerPutACard();
                nowPlaying = Durak.ME;
            }

            else
            {
                PopUp("You are the attacker ");
                setLabelTexts();
            }


        }
        public int findAttacker()
        {

            StackTrace stackTrace = new StackTrace();
            log(stackTrace.GetFrame(0).GetMethod().Name);
            int computerSmallTrumph = findLowestTrump(computerCards);
            int mySmallTrumph = findLowestTrump(myCards);

            if (computerSmallTrumph < mySmallTrumph)
            {
                attacker = Durak.COMPUTER;
                return Durak.COMPUTER;
            }
            attacker = Durak.ME;

            return Durak.ME;
        }

        public int findLowestTrump(List<CardBox> cards)
        {

            StackTrace stackTrace = new StackTrace();
            log(stackTrace.GetFrame(0).GetMethod().Name);
            int small = 999;
            foreach (CardBox card in cards)
            {
                Card playCard = card.getCard();
                if (playCard.Suit == trumpSuite)
                {
                    if (playCard.getCardRank() < small)
                    {
                        small = playCard.getCardRank();
                    }

                }
            }
            return small;

        }



        public void setUI(Form1 ui)
        {
            this.ui = ui;
        }

        public void PopUp(String message)
        {
            MessageBox.Show(message);
            log(message);
        }

        public void computerPutACard()
        {

            StackTrace stackTrace = new StackTrace();
            log(stackTrace.GetFrame(0).GetMethod().Name);
            if (gameOver)
            {
                return;
            }
            if (tableCards.Count() <= 0) // First chance, when no cards on the table
            {
                int cardNum = 0;
                if (computerCards.Count <= 0)
                {

                    return;
                }
                int rank = computerCards.ElementAt<CardBox>(cardNum).getCard().getCardRank();
                for (int i = 1; i < computerCards.Count(); i++)
                {
                    CardBox card = computerCards.ElementAt<CardBox>(i);
                    Card playCard = card.getCard();
                    if (playCard.getCardRank() > rank)
                    {
                        rank = playCard.getCardRank();
                        cardNum = i;
                    }

                }
                if (tableCards.Count() <= 0)
                {
                    //first play
                    putCardOnTable(computerCards, cardNum);

                }
                if (detectThrow() == false)
                {
                    nowPlaying = Durak.ME;
                }
                else
                {

                    PopUp("You have no card to put... so computer will continue");
                    throwCards(Durak.COMPUTER);
                    computerPutACard();
                    nowPlaying = Durak.COMPUTER;
                    while (detectThrow())
                    {
                        PopUp("You have no card to put... so computer will continue");

                        throwCards(Durak.COMPUTER);
                        nowPlaying = Durak.COMPUTER;
                        computerPutACard();
                    }
                    nowPlaying = Durak.ME;

                }
            }
            else
            {
                int cardNum = -1;
                for (int i = 0; i < computerCards.Count; i++)
                {
                    if (isValidMove(computerCards, i))
                    {
                        cardNum = i;
                        break;
                    }

                }
                if (cardNum != -1)
                {
                    putCardOnTable(computerCards, cardNum);
                    if (detectThrow() == false)
                    {
                        nowPlaying = Durak.ME;
                    }
                    else
                    {

                        PopUp("You have no card to put... so computer will continue");
                        throwCards(Durak.COMPUTER);
                        nowPlaying = Durak.COMPUTER;
                        computerPutACard();
                        while (detectThrow())
                        {
                            PopUp("You have no card to put... so computer will continue");
                            throwCards(Durak.COMPUTER);
                            nowPlaying = Durak.COMPUTER;
                            computerPutACard();
                        }
                        nowPlaying = Durak.ME;

                    }
                }
                else
                {
                    PopUp("Computer has no card to put, you can continue");
                    throwCards(Durak.ME);
                    nowPlaying = Durak.ME;

                }



            }

        }

        private void putCardOnTable(List<CardBox> cards, int clickedCardIndex)
        {

            StackTrace stackTrace = new StackTrace();
            log(stackTrace.GetFrame(0).GetMethod().Name);

            CardBox clickedCard = cards.ElementAt<CardBox>(clickedCardIndex);
            clickedCard.Visible = false;
            Card card = clickedCard.getCard();
            CardBox cardBox = new CardBox();


            cardBox.setCard(card);
            cardBox.Width = 94;
            cardBox.Height = 125;
            cardBox.BackgroundImageLayout = ImageLayout.Stretch;
            cardBox.flipCard();
            tableCards.Add(cardBox);

            int x = 10;
            int y = 10;
            foreach (CardBox tableCard in tableCards)
            {
                tableCard.SetBounds(x, y, 94, 125);

                table.Controls.Add(tableCard);
                tableCard.BringToFront();
                if (y == 10)
                {
                    y = 50;
                }
                else
                {
                    y = 10;
                    x += 100;
                }


            }

            cards.Remove(clickedCard);
            setLabelTexts();
            if (nowPlaying == Durak.ME)
            {
                arrangeMyCards();
            }
            else
            {
                arrangeComputerCards();
            }
            findWinner();

        }


        private void setLabelTexts()
        {

            StackTrace stackTrace = new StackTrace();
            log(stackTrace.GetFrame(0).GetMethod().Name);
            int computerCardsCount = computerCards.Count;//getVisibleCardCount(this.computerCards);
            computerCardsLeft.Text = "Cards Left : " + computerCardsCount;
            int myCardCount = myCards.Count;//getVisibleCardCount(this.myCards);
            myCardsLeft.Text = "Cards Left : " + myCardCount;
            if (top == 1)
            {
                remaingCardsLeft.Text = "Remaining Cards \n        " + (deck.NumberOfCards + 1);
            }
            else
            {
                remaingCardsLeft.Text = "Remaining Cards \n        0";
            }
            if (attacker == Durak.COMPUTER)
            {
                computerAttackerLabel.Visible = true;
                userAttackerLabel.Visible = false;
            }
            else
            {
                computerAttackerLabel.Visible = false;
                userAttackerLabel.Visible = true;
            }

        }

        public void throwCards(int fromPlayer)
        {

            StackTrace stackTrace = new StackTrace();
            log(stackTrace.GetFrame(0).GetMethod().Name);
            CardBox tableTopCard = tableCards.ElementAt<CardBox>(tableCards.Count - 1);
            Boolean takeCards = true;
            if (fromPlayer == Durak.COMPUTER && attacker == Durak.ME)
            {
                takeCards = false;
            }
            if (fromPlayer == Durak.ME && attacker == Durak.COMPUTER)
            {
                takeCards = false;
            }


            if (takeCards)
            {

                if (attacker == Durak.COMPUTER)
                {
                    PopUp("You need to take the card from table");
                    nowPlaying = Durak.COMPUTER;
                    takeCardsFromTable(myCards);
                }
                else
                {

                    PopUp("Computer takes the cards from table");
                    nowPlaying = Durak.ME;
                    takeCardsFromTable(computerCards);
                }

            }
            tableCards.Clear();
            table.Controls.Clear();
            addCardsFromDeck();

        }
        private Boolean detectThrow()
        {
            for (int i = 0; i < myCards.Count; i++)
            {
                if (isValidMove(myCards, i))
                    return false;

            }
            return true;

        }



        private void findWinner()
        {

            StackTrace stackTrace = new StackTrace();
            log(stackTrace.GetFrame(0).GetMethod().Name);

            if (deck.NumberOfCards == 0 && top == 0)
            {
                if (computerCards.Count == 0)
                {
                    PopUp("Computer Wins...");
                    writeWinner("computer");
                    gameOver = true;

                }
                else if (myCards.Count == 0)
                {
                    PopUp("Congrats ... You wins...");
                    writeWinner("user");
                    gameOver = true;
                }
            }
            else
            {
                if (deck.NumberOfCards == 0 && top != 0)
                {
                    addCardsFromDeck();
                }
            }
        }

        private void addCardsFromDeck()
        {

            StackTrace stackTrace = new StackTrace();
            log(stackTrace.GetFrame(0).GetMethod().Name);
            for (int i = computerCards.Count; i < 6; i++)
            {
                CardBox box = new CardBox();
                Card deckDard = deck.GetRandomCard();

                if (deckDard != null)
                {
                    box.setCard(deckDard);
                    this.computerCards.Add(box);
                }
                else
                {
                    if (top == 1)
                    {
                        // box = topCard;
                        box.setCard(topCard.getCard());
                        this.computerCards.Add(box);
                        topCard.Visible = false;
                        top = 0;

                    }
                    break;

                }


            }

            for (int i = myCards.Count; i < 6; i++)
            {

                CardBox box = new CardBox();
                box.Tag = i + 1;
                box.cardBoxClicked += (s, e) =>
                {

                    playGame((int)box.Tag);
                };
                Card deckDard = deck.GetRandomCard();
                if (deckDard != null)
                {
                    box.setCard(deckDard);
                    box.flipCard();
                    this.myCards.Add(box);
                }
                else
                {
                    if (top == 1)
                    {
                        //box = topCard;
                        box.setCard(topCard.getCard());
                        box.flipCard();
                        this.myCards.Add(box);
                        topCard.Visible = false;
                        top = 0;
                    }
                    break;
                }


            }
            arrangeComputerCards();
            arrangeMyCards();
            setLabelTexts();

        }

        private void takeCardsFromTable(List<CardBox> cards)
        {
            StackTrace stackTrace = new StackTrace();
            log(stackTrace.GetFrame(0).GetMethod().Name);
            int loopTill = cards.Count + tableCards.Count;
            int j = 0;
            for (int i = cards.Count - 1; i < loopTill - 1; i++)
            {
                CardBox box = tableCards.ElementAt<CardBox>(j);
                CardBox newCard = new CardBox();

                Card card = box.getCard();
                newCard.setCard(box.getCard());
                if (nowPlaying == Durak.ME)
                {

                }
                else
                {
                    //PopUp("Card Flipped");
                    newCard.flipCard();
                    newCard.Tag = i + 1;
                    newCard.cardBoxClicked += (s, e) =>
                    {

                        playGame((int)newCard.Tag);
                    };

                }
                cards.Add(newCard);
                j++;


            }
            arrangeComputerCards();
            arrangeMyCards();

        }
        public void log(String logMessage)
        {
            using (FileStream aFile = new FileStream(logFileName, FileMode.Append, FileAccess.Write))
            using (StreamWriter sw = new StreamWriter(aFile))
            {
                sw.Write("{0} {1}", DateTime.Now.ToLongTimeString(), DateTime.Now.ToLongDateString());
                sw.Write("  : ");
                sw.WriteLine(logMessage);

            }

        }

        public void clearLogFile()
        {
            System.IO.File.WriteAllText(logFileName, string.Empty);
        }

        private void writeWinner(String winnerName)
        {
            using (FileStream aFile = new FileStream("stat.txt", FileMode.Append, FileAccess.Write))
            using (StreamWriter sw = new StreamWriter(aFile))
            {
                sw.WriteLine(winnerName);

            }
        }
    }
   
}
